package be.kul.osgi.ds.myagent;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Schedule {

	public ArrayList<Commitment> sched;
	public Commitment current;
	
	public static Object sharedLock = new Object();
	
	public Schedule(){
		sched = new ArrayList<Commitment>();
	}
	
	public Commitment getFirst(){
		if(!sched.isEmpty())
		{
			return sched.get(0);
		}
		return null;
	}
	
	public boolean removeFirst(){
		if(!sched.isEmpty())
		{
			sched.remove(0);
			return true;
		}
		return false;
	}
	
	public void sort(){
		Collections.sort(sched, new CustomComparator());
	}
	
	public boolean add(Commitment c) throws IOException
	{
		if (fit(c)){
			Long start =  getStartTime(c);
			Long end =  start + c.time;
			c.start = start;
			c.end = end;
			sched.add(c);
			sort();
			return true;
		} else {
			System.out.println(sched);
			System.out.println("Just doesn't fit");
			return false;
		}
	}
	
	public boolean addback(Commitment c) throws IOException
	{
			int size = sched.size();
			Long start = sched.get(size-1).end ;
			Long end =  start + c.time;
			c.start = start;
			c.end = end;
			sched.add(c);
			System.out.println("added");
			//sort();
			return true;
	}
	
	public void delete(Commitment c){
		sched.remove(c);
	}
	
	public boolean fit(Commitment c) {
		
		Schedule sched_temp = new Schedule();
		sched_temp.sched = (ArrayList<Commitment>) this.sched.clone();
		
		int size = sched_temp.sched.size();
		if(sched_temp.sched.isEmpty()) {
			return true;
		}
		if(c.due >= (sched_temp.sched.get(size-1).end + c.getTime())){
			return true;
		}
		
		
		for(int i = 0; i < size; i++){
			//since the arraylist is sorted after every adding, the first violation of this test will also be violated every next iteration
			if(c.due <= sched.get(i).end) {
				return false;
			}
			if (i == (size -1)){
				if((sched.get(i).end + c.getTime()) <= c.getDue()){
					return true;
				} 
			} else if (i < size) {
				if(((sched.get(i+1).start - sched.get(i).end) >= c.getDue()) && (sched.get(i+1).start >= c.getDue()) ){
					return true;
				} 
			} else {
				return false;
			}
		}
		return false;
	}
	
	public long getStartTime(Commitment c) {
		
		Schedule sched_temp = new Schedule();
		sched_temp.sched = (ArrayList<Commitment>) this.sched.clone();
		
		int size = sched_temp.sched.size();
		//empty schedule
		if(sched_temp.sched.isEmpty()) {
			return c.agent.getTime();
		}
		
		//add at the end
		if(c.due >= (sched_temp.sched.get(size-1).end + c.getTime())){
			return sched_temp.sched.get(size-1).end;
		}
		
		
		for(int i = 0; i < size; i++){
			//since the arraylist is sorted after every adding, the first violation of this test will also be violated every next iteration
			//no fit at all
			if(c.due <= sched.get(i).end) {
				return -1;
			}
			//fits in between
			if (i == (size -1)){
				if((sched.get(i).end + c.getTime()) <= c.getDue()){
					return sched.get(i).end;
				} 
			} else if (i < size) {
				if(((sched.get(i+1).start - sched.get(i).end) >= c.getTime()) && (sched.get(i+1).start >= c.getDue()) ){
					return sched.get(i).end;
				} 
			} else {
				return -1;
			}
		}
		return -1;
	}
	
	public ArrayList<Commitment> reschedule(Commitment c) throws IOException{
		int size = sched.size();
		for(int i = 0; i < size; i++){
			Schedule sched_temp = new Schedule();
			//sched_temp = new Schedule();
			sched_temp.sched = (ArrayList<Commitment>) this.sched.clone();
			Commitment temp = sched_temp.sched.get(i);
			sched_temp.sched.remove(temp);
			if(sched_temp.fit(c)){
				sched_temp.sched.add(c);
				if (sched_temp.fit(temp)){
					sched_temp.sched.add(temp);
					sched_temp.sort();
					return sched_temp.sched;
				}
			}
		}
		return null;
	}

	public class CustomComparator implements Comparator<Commitment> {
		@Override
		public int compare(Commitment one, Commitment two) {
			if (one.start < two.start) {
				return -1;
			}else if (one.start > two.start){
				return 1;
			} else {
				return 0;
			}
		}
	}
	
}
